import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * @author 折戟沉沙铁未销
 * @version V1.0
 * @date 2025-05-30-2025
 * @Description: 这里用一句话描述这个类的作用
 */
public class Server {
    private ServerSocketChannel serverSocketChannel;
    private Selector selector;
    private ByteBuffer rBuffer = ByteBuffer.allocate(1024);
    private ByteBuffer wBuffer = ByteBuffer.allocate(1024);
    private Charset charset = StandardCharsets.UTF_8;
    private int port;

    public Server() {
        this.port = 6666;
    }

    public Server(int port) {
        this.port = port;
    }

    /* 启动服务 */
    public void start() throws IOException {
        try {
            // 创建 ServerSocketChannel
            serverSocketChannel = ServerSocketChannel.open();
            // 设置为 非阻塞
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.socket().bind(new InetSocketAddress(port));

            // 创建 selector
            selector = Selector.open();

            // 注册。关注 accept 事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                // select() 个方法是阻塞的
                selector.select();

                // 获取 selectedKeys。 即：获取到发生了哪些事件
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();

                    // 处理被触发的事件
                    handler(selectionKey);

                    // 清除 已经处理过的事件
                    selectionKeys.remove(selectionKey);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocketChannel != null) {
                selector.close();
            }
            if (selector != null) {
                selector.close();
            }
        }
    }

    /* 处理消息 */
    private void handler(SelectionKey key) throws IOException {
        // accept 事件：有客户端 连接。处理该事件
        if (key.isAcceptable()) {
            serverSocketChannel = (ServerSocketChannel) key.channel();
            SocketChannel socketChannel = serverSocketChannel.accept();
            // 设置 SocketChannel 非阻塞
            socketChannel.configureBlocking(false);
            // 注册 read 事件。
            socketChannel.register(selector, SelectionKey.OP_READ);
            System.out.println(socketChannel.socket().getInetAddress().getHostAddress() + ": " + socketChannel.socket().getPort() + " 上线了!!!");
        }
        // read 事件：客户端有数据过来了
        if (key.isReadable()) {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            // 获取客户端消息
            rBuffer.clear();
            while (socketChannel.read(rBuffer) > 0) ;
            rBuffer.flip();
            String msg = charset.decode(rBuffer).toString();

            // 校验用户消息是否正常
            if (StringUtils.isEmpty(msg)) {
                key.cancel();
                selector.wakeup();
            } else {
                // 转发消息
                forwardMessage(socketChannel, msg);
            }
            // 用户是否退出
            if (StringUtils.equals(msg, "bye")) {
                key.cancel();
                selector.wakeup();
                System.out.println(socketChannel.socket().getInetAddress().getHostAddress() + ": " + socketChannel.socket().getPort() + " 退出了!!!");
            }
        }
    }

    /* 转发消息 */
    private void forwardMessage(SocketChannel socketChannel, String msg) {
        // 获取selector 上注册的所有的channel
        Set<SelectionKey> keys = selector.keys();
        Iterator<SelectionKey> iterator = keys.iterator();
        // 遍历
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            // selectionKey 是有效的
            // channel 的类型是SocketChannel，即：客户端对应的channel
            if (key.isValid() && key.channel() instanceof SocketChannel) {
                SocketChannel getSocketChannel = (SocketChannel) key.channel();
                // 不是当前客户端
                if (getSocketChannel != socketChannel) {
                    try {
                        // 将消息 put 写到 wBuffer 中
                        wBuffer.clear();
                        wBuffer.put(charset.encode(msg));
                        // 翻转。 由写模式切换到读模式
                        // 切换到 读模式， 读取channel 中的数据，写出到其他的 socketChannel 中
                        wBuffer.flip();
                        while (wBuffer.hasRemaining()) {
                            getSocketChannel.write(wBuffer);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


    public static void main(String[] args) {
        Server server = new Server();
    }
}